﻿/********************************************************************
	created:	2012/12/30
	created:	30:12:2012   11:45
	filename: 	C:\GoodFrame\common\LightweightPool.h
	file path:	C:\GoodFrame\common
	file base:	LightweightPool
	file ext:	h
	author:		侯国江
	
	purpose:	轻量级因定元素数量的池，针对任何结构的池。安全、高效、方便。
	                     注意：在应用时不要执行 delete 本实例，危险。因为它用到的 m_lock 若被 delete 后，但使用 LightweightFixNumPool 实例的线程却不知道。
						 无 init 和 expand_pool

Android 环境下编译的疑难杂症：
	1、在 uninit() 中，deque<T*>::iterator it; 这一句是编译报错的：
		  解决方案： typename deque<T*>::iterator it;    // 在前面加个 typename 就好，在 eclips 编译中，未加 typename, 报错
*********************************************************************/

#ifndef LIGHT_WEIGHT_FIX_NUM_POOL_H
#define LIGHT_WEIGHT_FIX_NUM_POOL_H

#include <iostream>  // std::cout
#include <algorithm>

#include <atomic>
#include <deque>

using std::deque ;
using std::atomic;

// 注意：在应用时不要执行 delete 本实例，危险。因为它用到的 m_lock 若被 delete 后，但使用 LightweightFixNumPool 实例的线程却不知道。

template<typename T> 
class  LightweightFixNumPool
{
public:
	enum 
	{ 
		DEF_INIT_COUNT	=   256,	// 池的初始元素数量
		DEF_MAX_COUNT	= 25600,	// 池内元素的上限值
	};

	enum { AUTO_SHRINK_SERVICEPOOL = 300, // 5 分钟
		 };  

public:
	LightweightFixNumPool(const char* pszPoolName, int nInitElementCount=DEF_INIT_COUNT, int nMaxElementCount=DEF_MAX_COUNT);
	~LightweightFixNumPool(void);	// 在应用时不要执行 delete 本实例，危险。因为它用到的 m_lock 若被 delete 后，但使用 LightweightFixNumPool 实例的线程却不知道。

public:

	bool add(T* pNew);

	int Test(int** pp);

	// 获得是否允许收缩
	bool get_shrink_pool();

	// 设置是否允许收缩
	void set_shrink_pool(bool bShrinkPool);

	// 设置池内初始元素的数量
	void set_init_block_count(int nInitBlkCount);

	// 设置池内元素的上限值
	void set_max_block_count(int nMaxBlkCount);

	// 设置扩展失败次数
	void set_expand_fail_times(int iExpandFailTimes);

	// 设置扩展失败时的睡眠时间，以 ms 为单位
	void set_expand_fail_sleep_time(int iExpandFailSleepTime);

	// 使用定时器自动收缩池，定时器由别的类提供，很重要
	int use_timer_shrink_pool(int nAtLessShrinkCount = 512, float fShrinkParam = 0.5);

	bool	uninit();	

	// 出池
	bool retrieve(T** ppT);

	// 归池
	bool recycle(T* pT);

	// 获得池内当前元素的数量
	int get_current_element_count();

	// 获得出池的数量
	long long get_retrieve_count();

	// 获得归池的数量
	long long get_recycle_count();	

	// 显示所有的池信息
	void display_all_pool();

private:

	deque<T*>	m_stack;	// 池

	std::recursive_mutex   m_lock;		// 递归互斥，recursive（递归）
					
	char			m_szPoolName[128];

	float			m_fExpandParam;	// 扩展系数，收缩时只收至初始值乘以扩充系数之处

	atomic_int	m_nInitElementCount;		// 池内初始元素的数量
	atomic_int	m_nMaxElementCount;		// 池内元素的上限值

	atomic_int  m_lRetrieveCount;	// 出池的数量
	atomic_int  m_lRecycleCount;	// 归池的数量

	int		m_nExpandStep;			// 扩展步长，池内无元素时需要扩展的数量
	int		m_lPeriod;				// 定时收缩的时间间隔，以 ms 为单位

	int		m_iExpandFailTimes;		// 扩展失败次数
	int		m_iExpandFailSleepTime;	// 扩展失败时的睡眠时间，以 ms 为单位

	bool	m_bShrinkPool;	// 是否允许收缩
};

///////////////////////////////////////////////////////////////////////////

template<typename T> 
LightweightFixNumPool<T>::LightweightFixNumPool(const char* pszPoolName, int nInitElementCount, int nMaxElementCount)
{
	memset(m_szPoolName, 0, sizeof(m_szPoolName)); 
	sprintf(m_szPoolName, "%s", pszPoolName);

	m_nInitElementCount = nInitElementCount;	// 池的初始元素数量
	m_nMaxElementCount = nMaxElementCount;		// 池内元素的上限值

	if(m_nInitElementCount>=64)
		m_nExpandStep = m_nInitElementCount/10;
	else
		m_nExpandStep = m_nInitElementCount;

	m_lPeriod = 1000;	// 定时器每秒响应一次，但不一定收缩池，以 ms 为单位

	m_fExpandParam = 1.25;	// 扩展系数，收缩时只收至初始值乘以扩充系数之处

	m_iExpandFailTimes = 10;	// 扩展失败次数
	m_iExpandFailSleepTime = 1000;	// 扩展失败时的睡眠时间，以 ms 为单位

	m_lRetrieveCount = 0;	// 出池的数量
	m_lRecycleCount = 0;	// 归池的数量

	m_bShrinkPool = false;	// 不允许收缩
}


template<typename T> 
LightweightFixNumPool<T>::~LightweightFixNumPool(void)
{
	uninit();
}

/* --------------------------------------------------------------------------
函数说明：增加元素
传入参数：
nCount			需要扩展的尺寸
bLimitExpandLen	控制扩展的长度
返回值：
实际扩展的尺寸
/--------------------------------------------------------------------------*/
template<typename T>
bool LightweightFixNumPool<T>::add(T* pNew)
{
	if (!pNew)
		return false;

	std::lock_guard<std::recursive_mutex> guard(m_lock);

	m_stack.push_back(pNew);

	return true;
}

template<typename T>
int LightweightFixNumPool<T>::Test(int** pp)
{
	return 0;
}

// 获得是否允许收缩
template<typename T> 
bool LightweightFixNumPool<T>::get_shrink_pool()	
{
	return m_bShrinkPool;
}

// 设置是否允许收缩
template<typename T> 
void LightweightFixNumPool<T>::set_shrink_pool(bool bShrinkPool)	
{
	m_bShrinkPool = bShrinkPool;
}

// 设置池内初始元素的数量
template<typename T>
void LightweightFixNumPool<T>::set_init_block_count(int nInitBlkCount)
{
	m_nInitElementCount = nInitBlkCount;
}

// 设置池内元素的上限值
template<typename T>
void LightweightFixNumPool<T>::set_max_block_count(int nMaxBlkCount)
{
	m_nMaxElementCount = nMaxBlkCount;
}

// 设置扩展失败次数
template<typename T>
void LightweightFixNumPool<T>::set_expand_fail_times(int iExpandFailTimes)
{
	m_iExpandFailTimes = iExpandFailTimes;		
}

// 设置扩展失败时的睡眠时间，以 ms 为单位
template<typename T>
void LightweightFixNumPool<T>::set_expand_fail_sleep_time(int iExpandFailSleepTime)
{
	m_iExpandFailSleepTime = iExpandFailSleepTime;	
}

// 结束初始化，与 init() 成对出现
template<typename T>
bool LightweightFixNumPool<T>::uninit()
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);

	int iRes = 0;
	int	iCount = (int)m_stack.size();

	typename deque<T*>::iterator it;    // 在 eclips 编译中，未加 typename, 报错 

	T* pT = NULL;
	while((it=m_stack.begin()) != m_stack.end())
	{
		pT = (T*)(*it);
		if(pT)
		{
			m_stack.erase(it);
			delete pT;
		}
		else
		{
			printf("轻型池内有元素是空值 %s %s \n", __FUNCTION__, m_szPoolName);
			iRes = 10;
		}
	}

	if(iCount>0)
	{
		printf("%s 轻型池释放完毕 \n", m_szPoolName);
	}

	return (0==iRes);
}

/* --------------------------------------------------------------------------
函数说明：出池
传入参数：
	bIsWait		如果从池中取消息记录未能成功，等待 1000 毫秒
传出参数：
	ppT		出池的 T 实例
返回值：
	成功则返回 true，否则返回 false 。
--------------------------------------------------------------------------*/
template<typename T> 
bool LightweightFixNumPool<T>::retrieve(T** ppT)
{
	//std::lock_guard<std::recursive_mutex> guard(m_lock);

	*ppT = NULL;

	bool	bResult = false;

	T*	pT = NULL;

	if(m_stack.size() > 0)
	{
		pT = m_stack.front();
		m_stack.pop_front();  // 从池中将该记录移除，但该记录要传出并使用，所以不能 delete

		*ppT = pT;

		m_lRetrieveCount++;
		//InterlockedIncrement64(&m_lRetrieveCount);

		bResult = true;
	}
	else
	{
		assert(false);
		bResult = false;
	}

	return bResult;
}

/* --------------------------------------------------------------------------
 函数说明：归池
 传入参数：
 	pT	一条消息记录
 返回值：
 	成功则返回 true，否则返回 false 。
 --------------------------------------------------------------------------*/
template<typename T> 
bool LightweightFixNumPool<T>::recycle(T* pT)
{
	//std::lock_guard<std::recursive_mutex> guard(m_lock);

	bool	bResult = false;

	if(pT)
	{
		m_stack.push_back(pT);
		
		m_lRecycleCount++;
		//InterlockedIncrement64(&m_lRecycleCount);

		bResult = true;
	}
	else
	{
		bResult = false;
	}

	return bResult;
}

// 当前元素的数量
template<typename T> 
int LightweightFixNumPool<T>::get_current_element_count()
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);
	
	return static_cast<int>(m_stack.size());
}

// 获得出池的数量
template<typename T> 
long long LightweightFixNumPool<T>::get_retrieve_count()
{
	return m_lRetrieveCount;
}

// 获得归池的数量
template<typename T> 
long long LightweightFixNumPool<T>::get_recycle_count()
{
	return m_lRecycleCount;
}

// 显示所有的池信息
template<typename T> 
void LightweightFixNumPool<T>::display_all_pool()
{
	printf("  %s，出池数=%I64d 归池数=%I64d 池内当前元素=%d \n",
		m_szPoolName, 
		get_retrieve_count(),
		get_recycle_count(),
		get_current_element_count()
		);
}


#endif